package github.ziwukun.jsonql.lang;

import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;

class LimitJson {
	/**
	 * 从JSON字符串中获取数据并创建对象<br>
	 * JSON字符串形如：<br>
	 * <code>
	 * {
	 * 		"User":{
	 * 			"article":{
	 * 				"@size":10,
	 * 				"@page":1,
	 * 				"comment":{
	 * 					"@size":100,
	 * 					"offset":100,
	 * 				}
	 * 			},
	 * 			"@size":100,
	 * 			"@after":{
	 * 				"id":100000000
	 * 			}
	 * 		}
	 * }
	 * </code>
	 * @author Hugo.Yu
	 */
	static LimitImpl readJson(String json) {
		if(!JSONUtil.isJsonObj(json)) {
			throw new JsonQLFormatException(
				"创建Limit对象所需JSON字符串必须是JSON对象",
				"@limit语句语法错误-" + json);
		}
		
		// 获取JSON对象准备解析，并且校验JSON对象必须为有且仅有一个KEY
		JSONObject jsonObj = new JSONObject(json);
		if(jsonObj.keySet().size() != 1) {
			throw new JsonQLFormatException(
				"JsonQL语法错误，转换JsonQLLimit失败，key值有且仅有一个key",
				"@limit语句语法错误-" + json);
		}
		
		// 获取相关数据
		String model = jsonObj.keySet().iterator().next();
		Object limitDetailObj = jsonObj.get(model);
		if(limitDetailObj == null || !(limitDetailObj instanceof JSONObject)) {
			throw new JsonQLFormatException("JsonQL语法错误，转换Limit失败，value值需要为JSON对象",
			"@limit语句语法错误-" + json);
		}
		
		JSONObject limitDetailJson = (JSONObject)limitDetailObj;
		Integer size = getInteger(limitDetailJson, LimitSym.SIZE);
		Integer offset = getInteger(limitDetailJson, LimitSym.OFFSET);
		Integer page = getInteger(limitDetailJson, LimitSym.PAGE);
		
		//offset，page只能都不存在或者只能存在一个
		int notNullAmount = 0;
		if(offset != null) {
			notNullAmount++;
		}
		if(page != null) {
			notNullAmount++;
		}
		if(notNullAmount > 1) {
			throw new JsonQLFormatException(
				"JsonQLLimit对象offset，page，after只能都不存在或者只能存在一个",
				"@limit语法解析错误-" + json);
		}
		
		// 如果还有其他的子限制条件，则递归查找
		// 删除所有@开头的key和值，剩下的就是子限制条件
		List<Limit> subLimits = new LinkedList<Limit>();
		for (Entry<String, Object> kv : limitDetailJson.entrySet()) {
			// 子LIMIT的条件
			if(kv.getKey() != null && !kv.getKey().startsWith("@")) {
				JSONObject subLimitJson = new JSONObject();
				subLimitJson.set(kv.getKey(), kv.getValue());
				subLimits.add(readJson(subLimitJson.toString()));
			}
		}
		
		return new LimitImpl(model, size, offset, page, subLimits);
	}
	
	/**
	 * 获取JSON对象中的指定的符号的值，并转换成Integer类型<br>
	 * 不存在返回null，类型错误抛出JsonQLFormatException
	 * @param json
	 * @param symbol
	 * @return
	 */
	private static Integer getInteger(JSONObject json,LimitSym symbol) {
		Object value = json.get(symbol.atWord());
		if(value == null) {
			return null;
		}
		
		if(value instanceof Integer) {
			return (Integer)value;
		}
		
		throw new JsonQLFormatException(
			"JsonQL语法错误，" + symbol.atWord() + "的属性值应该为整数型数值",
			symbol.atWord() + "的属性值应该为整数型数值");
	}
	
	static String writeJson(LimitImpl limit) {
		JSONObject mainJson = new JSONObject();
		JSONObject valueJson = new JSONObject();
		mainJson.set(limit.model(), valueJson);
		
		if(limit.size() != null) {
			valueJson.set(LimitSym.SIZE.atWord(), limit.size());
		}
		if(limit.offset() != null) {
			valueJson.set(LimitSym.OFFSET.atWord(), limit.offset());
		}
		if(limit.page() != null) {
			valueJson.set(LimitSym.PAGE.atWord(), limit.page());
		}
		
		if(limit.childs != null && !limit.childs.isEmpty()) {
			for (Limit subJsonQLLimit : limit.childs) {
				JSONObject subLimitJson = new JSONObject(subJsonQLLimit.toJSONQL());
				String subKey = subLimitJson.keySet().iterator().next();
				Object subValue = subLimitJson.get(subKey);
				valueJson.set(subKey, subValue);
			}
		}
		return mainJson.toString();
	}
}
